વૈશ્વિક ડેવલપર્સ માટે સમવર્તી નિયંત્રણ પર એક વ્યાપક માર્ગદર્શિકા. લોક-આધારિત સિંક્રોનાઇઝેશન, મ્યુટેક્સ, સેમાફોર, ડેડલોક અને શ્રેષ્ઠ પ્રથાઓનું અન્વેષણ કરો.
સમવર્તીતામાં નિપુણતા: લોક-આધારિત સિંક્રોનાઇઝેશનમાં ઊંડાણપૂર્વકનું સંશોધન
એક વ્યસ્ત વ્યાવસાયિક રસોડાની કલ્પના કરો. બહુવિધ રસોઈયાઓ એકસાથે કામ કરી રહ્યા છે, બધાને ઘટકોના સામાન્ય ભંડારની જરૂર છે. જો બે રસોઈયા એક જ ક્ષણે દુર્લભ મસાલાનો છેલ્લો બરણી પકડવાનો પ્રયાસ કરે, તો તે કોને મળશે? શું થાય જો એક રસોઈયો રેસીપી કાર્ડ અપડેટ કરી રહ્યો હોય જ્યારે બીજો તેને વાંચી રહ્યો હોય, જેના પરિણામે અડધી લખેલી, અર્થહીન સૂચના મળે? આ રસોડાની અરાજકતા આધુનિક સોફ્ટવેર ડેવલપમેન્ટમાં કેન્દ્રીય પડકાર માટે એક સંપૂર્ણ સરખામણી છે: સમવર્તીતા.
આજના મલ્ટી-કોર પ્રોસેસર્સ, ડિસ્ટ્રિબ્યુટેડ સિસ્ટમ્સ અને અત્યંત પ્રતિભાવશીલ એપ્લિકેશન્સની દુનિયામાં, સમવર્તીતા—એક પ્રોગ્રામના વિવિધ ભાગોને અંતિમ પરિણામને અસર કર્યા વિના ક્રમની બહાર અથવા આંશિક ક્રમમાં ચલાવવાની ક્ષમતા—એ લક્ઝરી નથી; તે એક આવશ્યકતા છે. તે ઝડપી વેબ સર્વર્સ, સરળ યુઝર ઇન્ટરફેસ અને શક્તિશાળી ડેટા પ્રોસેસિંગ પાઇપલાઇન્સ પાછળનું એન્જિન છે. જોકે, આ શક્તિ નોંધપાત્ર જટિલતા સાથે આવે છે. જ્યારે બહુવિધ થ્રેડો અથવા પ્રક્રિયાઓ એકસાથે શેર કરેલા સંસાધનોને ઍક્સેસ કરે છે, ત્યારે તેઓ એકબીજામાં દખલ કરી શકે છે, જેનાથી ડેટા ભ્રષ્ટ થાય છે, અણધારી વર્તણૂક થાય છે અને ગંભીર સિસ્ટમ નિષ્ફળતા થાય છે. આ તે છે જ્યાં સમવર્તી નિયંત્રણ કામમાં આવે છે.
આ વ્યાપક માર્ગદર્શિકા આ નિયંત્રિત અરાજકતાનું સંચાલન કરવા માટે સૌથી મૂળભૂત અને વ્યાપકપણે ઉપયોગમાં લેવાતી તકનીકનું અન્વેષણ કરશે: લોક-આધારિત સિંક્રોનાઇઝેશન. આપણે લોક્સ શું છે તે સમજાવીશું, તેમના વિવિધ સ્વરૂપોનું અન્વેષણ કરીશું, તેમની જોખમી ખામીઓને નેવિગેટ કરીશું અને મજબૂત, સલામત અને કાર્યક્ષમ સમવર્તી કોડ લખવા માટે વૈશ્વિક શ્રેષ્ઠ પ્રથાઓનો સમૂહ સ્થાપિત કરીશું.
સમવર્તી નિયંત્રણ શું છે?
તેના મૂળમાં, સમવર્તી નિયંત્રણ એ કમ્પ્યુટર વિજ્ઞાનમાં એક શિસ્ત છે જે શેર કરેલા ડેટા પર એકસાથે થતી કામગીરીનું સંચાલન કરવા માટે સમર્પિત છે. તેનો પ્રાથમિક ધ્યેય એ સુનિશ્ચિત કરવાનો છે કે સમવર્તી કામગીરી એકબીજામાં દખલ કર્યા વિના, ડેટાની અખંડિતતા અને સુસંગતતા જાળવી રાખીને, યોગ્ય રીતે કાર્ય કરે. તેને રસોડાના મેનેજર તરીકે વિચારો જે રસોઈયાઓ પેન્ટ્રીને કેવી રીતે ઍક્સેસ કરી શકે છે તે માટે નિયમો સેટ કરે છે જેથી છલકાવવું, ગેરસમજ અને બગડેલા ઘટકોને અટકાવી શકાય.
ડેટાબેસેસની દુનિયામાં, ACID ગુણધર્મો (એટોમિસિટી, કન્સિસ્ટન્સી, આઇસોલેશન, ડ્યુરેબિલિટી), ખાસ કરીને આઇસોલેશન જાળવવા માટે સમવર્તી નિયંત્રણ આવશ્યક છે. આઇસોલેશન સુનિશ્ચિત કરે છે કે ટ્રાન્ઝેક્શન્સના સમવર્તી એક્ઝિક્યુશનના પરિણામે સિસ્ટમની એવી સ્થિતિ પ્રાપ્ત થાય છે જે ટ્રાન્ઝેક્શન્સને એક પછી એક ક્રમિક રીતે એક્ઝિક્યુટ કરવામાં આવે તો પ્રાપ્ત થશે.
સમવર્તી નિયંત્રણના અમલીકરણ માટે બે પ્રાથમિક ફિલોસોફી છે:
- આશાવાદી સમવર્તી નિયંત્રણ: આ અભિગમ માને છે કે વિવાદો દુર્લભ છે. તે કોઈપણ અગાઉની તપાસ વિના કામગીરીને આગળ વધારવાની મંજૂરી આપે છે. ફેરફારને પ્રતિબદ્ધ કરતા પહેલા, સિસ્ટમ ચકાસે છે કે અન્ય કોઈ કામગીરીએ તે દરમિયાન ડેટામાં ફેરફાર કર્યો છે કે નહીં. જો કોઈ વિવાદ જણાય, તો કામગીરી સામાન્ય રીતે રોલ બેક કરવામાં આવે છે અને ફરીથી પ્રયાસ કરવામાં આવે છે. તે "માફી માંગો, પરવાનગી નહીં" ની વ્યૂહરચના છે.
- નિરાશાવાદી સમવર્તી નિયંત્રણ: આ અભિગમ માને છે કે વિવાદો સંભવિત છે. તે ઑપરેશનને સંસાધનને ઍક્સેસ કરતા પહેલા તેના પર લોક મેળવવા દબાણ કરે છે, અન્ય ઑપરેશનને દખલ કરતા અટકાવે છે. તે "પરવાનગી માંગો, માફી નહીં" ની વ્યૂહરચના છે.
આ લેખ ફક્ત નિરાશાવાદી અભિગમ પર ધ્યાન કેન્દ્રિત કરે છે, જે લોક-આધારિત સિંક્રોનાઇઝેશનનો પાયો છે.
મુખ્ય સમસ્યા: રેસ કન્ડિશન્સ
આપણે ઉકેલને સમજી શકીએ તે પહેલાં, આપણે સમસ્યાને સંપૂર્ણપણે સમજવી જોઈએ. સમવર્તી પ્રોગ્રામિંગમાં સૌથી સામાન્ય અને કપટી બગ એ રેસ કન્ડિશન છે. રેસ કન્ડિશન ત્યારે થાય છે જ્યારે સિસ્ટમનું વર્તન અનિયંત્રિત ઘટનાઓના અણધારી ક્રમ અથવા સમય પર આધાર રાખે છે, જેમ કે ઓપરેટિંગ સિસ્ટમ દ્વારા થ્રેડોનું શેડ્યુલિંગ.
ચાલો ક્લાસિક ઉદાહરણ ધ્યાનમાં લઈએ: એક શેર કરેલું બેંક ખાતું. ધારો કે એક ખાતામાં $1000 નું બેલેન્સ છે, અને બે સમવર્તી થ્રેડો દરેક $100 જમા કરવાનો પ્રયાસ કરે છે.
અહીં ડિપોઝિટ માટેની કામગીરીનો એક સરળ ક્રમ છે:
- મેમરીમાંથી વર્તમાન બેલેન્સ વાંચો.
- આ મૂલ્યમાં ડિપોઝિટની રકમ ઉમેરો.
- નવું મૂલ્ય મેમરીમાં પાછું લખો.
યોગ્ય, ક્રમિક એક્ઝિક્યુશનના પરિણામે $1200 નું અંતિમ બેલેન્સ મળશે. પરંતુ સમવર્તી દૃશ્યમાં શું થાય છે?
કામગીરીનો સંભવિત આંતરપ્રવાહ:
- થ્રેડ A: બેલેન્સ વાંચે છે ($1000).
- કન્ટેક્સ્ટ સ્વિચ: ઓપરેટિંગ સિસ્ટમ થ્રેડ A ને થોભાવે છે અને થ્રેડ B ચલાવે છે.
- થ્રેડ B: બેલેન્સ વાંચે છે (હજુ પણ $1000).
- થ્રેડ B: તેનું નવું બેલેન્સ ગણતરી કરે છે ($1000 + $100 = $1100).
- થ્રેડ B: નવું બેલેન્સ ($1100) મેમરીમાં પાછું લખે છે.
- કન્ટેક્સ્ટ સ્વિચ: ઓપરેટિંગ સિસ્ટમ થ્રેડ A ફરી શરૂ કરે છે.
- થ્રેડ A: તેણે અગાઉ વાંચેલા મૂલ્યના આધારે તેનું નવું બેલેન્સ ગણતરી કરે છે ($1000 + $100 = $1100).
- થ્રેડ A: નવું બેલેન્સ ($1100) મેમરીમાં પાછું લખે છે.
અંતિમ બેલેન્સ $1100 છે, જે અપેક્ષિત $1200 નથી. રેસ કન્ડિશનને કારણે $100 ની ડિપોઝિટ હવામાં અદૃશ્ય થઈ ગઈ છે. કોડનો બ્લોક જ્યાં શેર કરેલા સંસાધન (એકાઉન્ટ બેલેન્સ) ને ઍક્સેસ કરવામાં આવે છે તેને ક્રિટિકલ સેક્શન તરીકે ઓળખવામાં આવે છે. રેસ કન્ડિશનને રોકવા માટે, આપણે સુનિશ્ચિત કરવું જોઈએ કે કોઈપણ સમયે ફક્ત એક જ થ્રેડ ક્રિટિકલ સેક્શનમાં એક્ઝિક્યુટ થઈ શકે. આ સિદ્ધાંતને પરસ્પર બાકાત કહેવામાં આવે છે.
લોક-આધારિત સિંક્રોનાઇઝેશનનો પરિચય
લોક-આધારિત સિંક્રોનાઇઝેશન એ પરસ્પર બાકાત લાગુ કરવા માટેની પ્રાથમિક પદ્ધતિ છે. લોક (જેને મ્યુટેક્સ પણ કહેવાય છે) એ એક સિંક્રોનાઇઝેશન પ્રિમિટિવ છે જે નિર્ણાયક વિભાગ માટે રક્ષક તરીકે કાર્ય કરે છે.
એક વ્યક્તિ માટેના શૌચાલયની ચાવીની સરખામણી ખૂબ જ યોગ્ય છે. શૌચાલય એ નિર્ણાયક વિભાગ છે, અને ચાવી એ લોક છે. ઘણા લોકો (થ્રેડો) બહાર રાહ જોઈ રહ્યા હોઈ શકે છે, પરંતુ ફક્ત ચાવી ધરાવનાર વ્યક્તિ જ અંદર પ્રવેશી શકે છે. જ્યારે તેઓ તેમનું કામ પૂરું કરે છે, ત્યારે તેઓ બહાર નીકળી જાય છે અને ચાવી પાછી આપે છે, જેનાથી કતારમાંનો આગલો વ્યક્તિ તેને લઈ શકે અને અંદર પ્રવેશી શકે.
લોક્સ બે મૂળભૂત કામગીરીને સપોર્ટ કરે છે:
- મેળવો (અથવા લોક): નિર્ણાયક વિભાગમાં પ્રવેશતા પહેલા એક થ્રેડ આ કામગીરીને કોલ કરે છે. જો લોક ઉપલબ્ધ હોય, તો થ્રેડ તેને મેળવે છે અને આગળ વધે છે. જો લોક પહેલાથી જ બીજા થ્રેડ દ્વારા રાખવામાં આવ્યું હોય, તો કોલિંગ થ્રેડ લોક મુક્ત ન થાય ત્યાં સુધી બ્લોક થશે (અથવા "ઊંઘી જશે").
- છોડો (અથવા અનલોક): નિર્ણાયક વિભાગનું એક્ઝિક્યુશન પૂર્ણ કર્યા પછી એક થ્રેડ આ કામગીરીને કોલ કરે છે. આ અન્ય રાહ જોઈ રહેલા થ્રેડોને મેળવવા માટે લોક ઉપલબ્ધ બનાવે છે.
અમારા બેંક ખાતાના તર્કને લોક સાથે લપેટીને, અમે તેની શુદ્ધતાની ખાતરી આપી શકીએ છીએ:
acquire_lock(account_lock);
// --- નિર્ણાયક વિભાગ શરૂ ---
balance = read_balance();
new_balance = balance + amount;
write_balance(new_balance);
// --- નિર્ણાયક વિભાગ સમાપ્ત ---
release_lock(account_lock);
હવે, જો થ્રેડ A લોક પહેલા મેળવે છે, તો થ્રેડ B ને થ્રેડ A ત્રણેય પગલાં પૂર્ણ કરે અને લોક છોડે ત્યાં સુધી રાહ જોવાની ફરજ પડશે. કામગીરી હવે આંતરપ્રવાહિત નથી, અને રેસ કન્ડિશન દૂર થઈ ગઈ છે.
લોક્સના પ્રકારો: પ્રોગ્રામરની ટૂલકિટ
જ્યારે લોકનો મૂળભૂત ખ્યાલ સરળ છે, ત્યારે વિવિધ દૃશ્યોમાં વિવિધ પ્રકારની લોકિંગ મિકેનિઝમ્સની જરૂર પડે છે. ઉપલબ્ધ લોક્સની ટૂલકિટને સમજવું કાર્યક્ષમ અને યોગ્ય સમવર્તી સિસ્ટમ્સ બનાવવા માટે નિર્ણાયક છે.
મ્યુટેક્સ (પરસ્પર બાકાત) લોક્સ
મ્યુટેક્સ એ સૌથી સરળ અને સૌથી સામાન્ય પ્રકારનું લોક છે. તે બાયનરી લોક છે, એટલે કે તેની ફક્ત બે સ્થિતિઓ છે: લોક કરેલું અથવા અનલોક કરેલું. તે કડક પરસ્પર બાકાત લાગુ કરવા માટે રચાયેલ છે, તે સુનિશ્ચિત કરે છે કે કોઈપણ સમયે ફક્ત એક જ થ્રેડ લોક ધરાવી શકે.
- માલિકી: મોટાભાગના મ્યુટેક્સ અમલીકરણની મુખ્ય લાક્ષણિકતા માલિકી છે. જે થ્રેડ મ્યુટેક્સ મેળવે છે તે એકમાત્ર થ્રેડ છે જેને તેને છોડવાની મંજૂરી છે. આ એક થ્રેડને અજાણતા (અથવા દૂષિત રીતે) બીજા દ્વારા ઉપયોગમાં લેવાતા નિર્ણાયક વિભાગને અનલોક કરતા અટકાવે છે.
- ઉપયોગ કેસ: શેર કરેલા ચલને અપડેટ કરવા અથવા ડેટા સ્ટ્રક્ચરમાં ફેરફાર કરવા જેવા ટૂંકા, સરળ નિર્ણાયક વિભાગોને સુરક્ષિત કરવા માટે મ્યુટેક્સ ડિફોલ્ટ પસંદગી છે.
સેમાફોર
સેમાફોર એ ડચ કમ્પ્યુટર વૈજ્ઞાનિક એડ્ઝર ડબલ્યુ. ડાઇકસ્ટ્રા દ્વારા શોધાયેલ એક વધુ સામાન્યકૃત સિંક્રોનાઇઝેશન પ્રિમિટિવ છે. મ્યુટેક્સથી વિપરીત, સેમાફોર બિન-ઋણાત્મક પૂર્ણાંક મૂલ્યનું કાઉન્ટર જાળવી રાખે છે.
તે બે એટોમિક કામગીરીને સપોર્ટ કરે છે:
- wait() (અથવા P કામગીરી): સેમાફોરના કાઉન્ટરને ઘટાડે છે. જો કાઉન્ટર નકારાત્મક બને છે, તો કાઉન્ટર શૂન્ય કરતાં વધુ અથવા સમાન ન થાય ત્યાં સુધી થ્રેડ બ્લોક થાય છે.
- signal() (અથવા V કામગીરી): સેમાફોરના કાઉન્ટરને વધારે છે. જો સેમાફોર પર કોઈ થ્રેડ બ્લોક થયેલ હોય, તો તેમાંથી એક અનબ્લોક થાય છે.
સેમાફોરના બે મુખ્ય પ્રકાર છે:
- બાયનરી સેમાફોર: કાઉન્ટર 1 પર પ્રારંભિક કરવામાં આવે છે. તે ફક્ત 0 અથવા 1 હોઈ શકે છે, જે તેને કાર્યાત્મક રીતે મ્યુટેક્સની સમકક્ષ બનાવે છે.
- કાઉન્ટિંગ સેમાફોર: કાઉન્ટરને કોઈપણ પૂર્ણાંક N > 1 પર પ્રારંભિક કરી શકાય છે. આ N જેટલા થ્રેડોને સંસાધનને સમવર્તી રીતે ઍક્સેસ કરવાની મંજૂરી આપે છે. તેનો ઉપયોગ સંસાધનોના મર્યાદિત પૂલ સુધી પહોંચને નિયંત્રિત કરવા માટે થાય છે.
ઉદાહરણ: એક વેબ એપ્લિકેશનની કલ્પના કરો જેમાં કનેક્શન પૂલ હોય જે મહત્તમ 10 સમવર્તી ડેટાબેઝ કનેક્શન્સને હેન્ડલ કરી શકે છે. 10 પર પ્રારંભિક કરેલ કાઉન્ટિંગ સેમાફોર આનું સંપૂર્ણ સંચાલન કરી શકે છે. દરેક થ્રેડ કનેક્શન લેતા પહેલા સેમાફોર પર `wait()` કરવું આવશ્યક છે. 11મો થ્રેડ ત્યાં સુધી બ્લોક રહેશે જ્યાં સુધી પ્રથમ 10 થ્રેડોમાંથી કોઈ એક તેનું ડેટાબેઝ કાર્ય પૂર્ણ ન કરે અને સેમાફોર પર `signal()` ન કરે, કનેક્શનને પૂલમાં પાછું ન આપે.
રીડ-રાઇટ લોક્સ (શેર કરેલા/એક્સક્લુઝિવ લોક્સ)
સમવર્તી સિસ્ટમ્સમાં એક સામાન્ય પેટર્ન એ છે કે ડેટા લખવા કરતાં ઘણી વાર વાંચવામાં આવે છે. આ દૃશ્યમાં સરળ મ્યુટેક્સનો ઉપયોગ અક્ષમ છે, કારણ કે તે બહુવિધ થ્રેડોને એકસાથે ડેટા વાંચતા અટકાવે છે, ભલે વાંચન સલામત, બિન-ફેરફાર કરતું ઓપરેશન હોય.
એક રીડ-રાઇટ લોક બે લોકિંગ મોડ્સ પ્રદાન કરીને આને સંબોધે છે:
- શેર કરેલ (વાંચન) લોક: બહુવિધ થ્રેડો એકસાથે રીડ લોક મેળવી શકે છે, જ્યાં સુધી કોઈ થ્રેડ રાઇટ લોક ન ધરાવતો હોય. આ ઉચ્ચ-સમવર્તી વાંચનની મંજૂરી આપે છે.
- એક્સક્લુઝિવ (લેખન) લોક: એક સમયે ફક્ત એક જ થ્રેડ રાઇટ લોક મેળવી શકે છે. જ્યારે કોઈ થ્રેડ રાઇટ લોક ધરાવે છે, ત્યારે અન્ય તમામ થ્રેડો (વાચકો અને લેખકો બંને) બ્લોક થાય છે.
આ સરખામણી શેર કરેલી લાઇબ્રેરીમાંના દસ્તાવેજ જેવી છે. ઘણા લોકો એક જ સમયે દસ્તાવેજની નકલો વાંચી શકે છે (શેર કરેલ રીડ લોક). જોકે, જો કોઈ વ્યક્તિ દસ્તાવેજને સંપાદિત કરવા માંગે છે, તો તેઓએ તેને વિશિષ્ટ રીતે તપાસવું આવશ્યક છે, અને જ્યાં સુધી તેઓ સમાપ્ત ન થાય ત્યાં સુધી કોઈ અન્ય તેને વાંચી અથવા સંપાદિત કરી શકશે નહીં (એક્સક્લુઝિવ રાઇટ લોક).
રિકર્સિવ લોક્સ (રિએન્ટ્રન્ટ લોક્સ)
જો કોઈ થ્રેડ કે જેણે પહેલેથી જ મ્યુટેક્સ પકડ્યો છે, તે તેને ફરીથી મેળવવાનો પ્રયાસ કરે તો શું થાય? પ્રમાણભૂત મ્યુટેક્સ સાથે, આના પરિણામે તાત્કાલિક ડેડલોક થશે—થ્રેડ પોતાને લોક મુક્ત કરવા માટે અનંતકાળ સુધી રાહ જોશે. એક રિકર્સિવ લોક (અથવા રિએન્ટ્રન્ટ લોક) આ સમસ્યાને ઉકેલવા માટે રચાયેલ છે.
રિકર્સિવ લોક સમાન થ્રેડને સમાન લોક બહુવિધ વખત મેળવવાની મંજૂરી આપે છે. તે આંતરિક માલિકી કાઉન્ટર જાળવી રાખે છે. લોક ત્યારે જ સંપૂર્ણપણે મુક્ત થાય છે જ્યારે માલિક થ્રેડે `acquire()` જેટલી જ વાર `release()` ને કોલ કર્યો હોય. આ ખાસ કરીને રિકર્સિવ ફંક્શન્સમાં ઉપયોગી છે જેમને તેમના એક્ઝિક્યુશન દરમિયાન શેર કરેલા સંસાધનને સુરક્ષિત કરવાની જરૂર હોય છે.
લોકિંગના ભયસ્થાનો: સામાન્ય ખામીઓ
જ્યારે લોક્સ શક્તિશાળી છે, ત્યારે તે બેધારી તલવાર છે. લોક્સનો અયોગ્ય ઉપયોગ એવી ભૂલો તરફ દોરી શકે છે જે સરળ રેસ કન્ડિશન્સ કરતાં નિદાન અને સુધારવામાં ઘણી વધુ મુશ્કેલ હોય છે. આમાં ડેડલોક, લાઇવલોક અને પર્ફોર્મન્સ બોટલનેકનો સમાવેશ થાય છે.
ડેડલોક
ડેડલોક એ સમવર્તી પ્રોગ્રામિંગમાં સૌથી ભયાવહ દૃશ્ય છે. તે ત્યારે થાય છે જ્યારે બે કે તેથી વધુ થ્રેડો અનિશ્ચિત સમય માટે બ્લોક થઈ જાય છે, દરેક સમાન સેટમાં બીજા થ્રેડ દ્વારા રાખવામાં આવેલા સંસાધનની રાહ જોતા હોય છે.
બે થ્રેડો (થ્રેડ 1, થ્રેડ 2) અને બે લોક્સ (લોક A, લોક B) સાથેના સરળ દૃશ્યનો વિચાર કરો:
- થ્રેડ 1 લોક A મેળવે છે.
- થ્રેડ 2 લોક B મેળવે છે.
- થ્રેડ 1 હવે લોક B મેળવવાનો પ્રયાસ કરે છે, પરંતુ તે થ્રેડ 2 દ્વારા રાખવામાં આવ્યું છે, તેથી થ્રેડ 1 બ્લોક થાય છે.
- થ્રેડ 2 હવે લોક A મેળવવાનો પ્રયાસ કરે છે, પરંતુ તે થ્રેડ 1 દ્વારા રાખવામાં આવ્યું છે, તેથી થ્રેડ 2 બ્લોક થાય છે.
બંને થ્રેડો હવે કાયમી રાહ જોવાના મોડમાં અટવાઈ ગયા છે. એપ્લિકેશન અટકી જાય છે. આ પરિસ્થિતિ ચાર આવશ્યક શરતો (કોફમેન શરતો) ની હાજરીમાંથી ઉદ્ભવે છે:
- પરસ્પર બાકાત: સંસાધનો (લોક્સ) શેર કરી શકાતા નથી.
- ધરો અને રાહ જુઓ: એક થ્રેડ બીજા સંસાધનની રાહ જોતી વખતે ઓછામાં ઓછો એક સંસાધન ધરાવે છે.
- પ્રિએમ્પ્શન નહીં: સંસાધનને ધારણ કરનાર થ્રેડ પાસેથી બળજબરીથી લઈ શકાય નહીં.
- વર્તુળાકાર રાહ: બે કે તેથી વધુ થ્રેડોની એક શૃંખલા અસ્તિત્વમાં છે, જ્યાં દરેક થ્રેડ શૃંખલામાંના આગલા થ્રેડ દ્વારા રાખવામાં આવેલા સંસાધનની રાહ જોઈ રહ્યો છે.
ડેડલોકને અટકાવવામાં આમાંની ઓછામાં ઓછી એક શરત તોડવાનો સમાવેશ થાય છે. સૌથી સામાન્ય વ્યૂહરચના એ છે કે લોક પ્રાપ્તિ માટે કડક વૈશ્વિક ક્રમ લાગુ કરીને વર્તુળાકાર રાહની સ્થિતિને તોડવી.
લાઇવલોક
લાઇવલોક એ ડેડલોકનો વધુ સૂક્ષ્મ સંબંધી છે. લાઇવલોકમાં, થ્રેડો બ્લોક થતા નથી—તેઓ સક્રિયપણે ચાલી રહ્યા હોય છે—પરંતુ તેઓ કોઈ પ્રગતિ કરતા નથી. તેઓ એકબીજાના રાજ્ય ફેરફારોને પ્રતિસાદ આપવાની લૂપમાં અટવાઈ જાય છે, કોઈ ઉપયોગી કાર્ય કર્યા વિના.
ક્લાસિક સરખામણી એ છે કે બે લોકો સાંકડા દાદરામાં એકબીજાને પસાર કરવાનો પ્રયાસ કરી રહ્યા છે. તેઓ બંને નમ્ર બનવાનો પ્રયાસ કરે છે અને તેમની ડાબી બાજુએ પગ મૂકે છે, પરંતુ તેઓ એકબીજાને અવરોધે છે. પછી તેઓ બંને તેમની જમણી બાજુએ પગ મૂકે છે, ફરીથી એકબીજાને અવરોધે છે. તેઓ સક્રિયપણે આગળ વધી રહ્યા છે પરંતુ દાદરામાં પ્રગતિ કરી રહ્યા નથી. સોફ્ટવેરમાં, આ નબળી રીતે ડિઝાઇન કરાયેલ ડેડલોક પુનઃપ્રાપ્તિ મિકેનિઝમ્સ સાથે થઈ શકે છે જ્યાં થ્રેડો વારંવાર પાછા ફરે છે અને ફરી પ્રયાસ કરે છે, ફક્ત ફરીથી વિવાદ કરવા માટે.
સ્ટાર્વેશન
સ્ટાર્વેશન ત્યારે થાય છે જ્યારે કોઈ થ્રેડને જરૂરી સંસાધનની ઍક્સેસ કાયમ માટે નકારવામાં આવે છે, ભલે સંસાધન ઉપલબ્ધ થાય. આ "નિષ્પક્ષ" ન હોય તેવા શેડ્યુલિંગ અલ્ગોરિધમ્સવાળી સિસ્ટમ્સમાં થઈ શકે છે. ઉદાહરણ તરીકે, જો લોકિંગ મિકેનિઝમ હંમેશા ઉચ્ચ-પ્રાથમિકતાવાળા થ્રેડોને ઍક્સેસ આપે છે, તો જો ઉચ્ચ-પ્રાથમિકતાવાળા દાવેદારોનો સતત પ્રવાહ હોય તો ઓછા-પ્રાથમિકતાવાળા થ્રેડને ક્યારેય ચાલવાની તક ન મળે.
પર્ફોર્મન્સ ઓવરહેડ
લોક્સ મફત નથી. તેઓ ઘણી રીતે પર્ફોર્મન્સ ઓવરહેડ રજૂ કરે છે:
- પ્રાપ્તિ/મુક્તિ ખર્ચ: લોક મેળવવાની અને મુક્ત કરવાની ક્રિયામાં એટોમિક કામગીરી અને મેમરી ફેન્સીનો સમાવેશ થાય છે, જે સામાન્ય સૂચનાઓ કરતાં વધુ કોમ્પ્યુટેશનલી ખર્ચાળ હોય છે.
- સ્પર્ધા: જ્યારે બહુવિધ થ્રેડો વારંવાર સમાન લોક માટે સ્પર્ધા કરતા હોય છે, ત્યારે સિસ્ટમ ઉત્પાદક કાર્ય કરવાને બદલે કન્ટેક્સ્ટ સ્વિચિંગ અને થ્રેડો શેડ્યુલિંગ પર નોંધપાત્ર સમય વિતાવે છે. ઉચ્ચ સ્પર્ધા અસરકારક રીતે એક્ઝિક્યુશનને સીરીયલાઈઝ કરે છે, સમાંતરતાના હેતુને હરાવી દે છે.
લોક-આધારિત સિંક્રોનાઇઝેશન માટે શ્રેષ્ઠ પ્રથાઓ
લોક્સ સાથે સાચો અને કાર્યક્ષમ સમવર્તી કોડ લખવા માટે શિસ્ત અને શ્રેષ્ઠ પ્રથાઓના સમૂહનું પાલન જરૂરી છે. આ સિદ્ધાંતો પ્રોગ્રામિંગ ભાષા અથવા પ્લેટફોર્મને ધ્યાનમાં લીધા વિના સાર્વત્રિક રીતે લાગુ પડે છે.
1. નિર્ણાયક વિભાગોને નાના રાખો
લોકને શક્ય તેટલા ઓછા સમય માટે પકડી રાખવું જોઈએ. તમારા નિર્ણાયક વિભાગમાં ફક્ત તે જ કોડ હોવો જોઈએ જેને સમવર્તી ઍક્સેસથી સુરક્ષિત રાખવો આવશ્યક છે. કોઈપણ બિન-નિર્ણાયક કામગીરી (જેમ કે I/O, શેર કરેલ સ્થિતિને સંડોવતા ન હોય તેવી જટિલ ગણતરીઓ) લોક કરેલા પ્રદેશની બહાર કરવી જોઈએ. તમે જેટલો લાંબો લોક પકડી રાખો છો, તેટલી સ્પર્ધાની શક્યતા વધારે છે અને તમે વધુ થ્રેડોને બ્લોક કરો છો.
2. યોગ્ય લોક દાણાદારતા પસંદ કરો
લોક દાણાદારતા એક જ લોક દ્વારા સુરક્ષિત ડેટાના જથ્થાનો સંદર્ભ આપે છે.
- મોટા-દાણાવાળા લોકિંગ: મોટી ડેટા સ્ટ્રક્ચર અથવા સમગ્ર સબસિસ્ટમને સુરક્ષિત કરવા માટે એક જ લોકનો ઉપયોગ કરવો. આ અમલીકરણ અને સમજાવવા માટે સરળ છે પરંતુ ઉચ્ચ સ્પર્ધા તરફ દોરી શકે છે, કારણ કે ડેટાના વિવિધ ભાગો પરની અસંબંધિત કામગીરી બધી જ સમાન લોક દ્વારા સીરીયલાઇઝ થાય છે.
- ઝીણા-દાણાવાળા લોકિંગ: ડેટા સ્ટ્રક્ચરના વિવિધ, સ્વતંત્ર ભાગોને સુરક્ષિત કરવા માટે બહુવિધ લોક્સનો ઉપયોગ કરવો. ઉદાહરણ તરીકે, સમગ્ર હેશ ટેબલ માટે એક લોકને બદલે, તમે દરેક બકેટ માટે અલગ લોક રાખી શકો છો. આ વધુ જટિલ છે પરંતુ વધુ સાચા સમાંતરતાને મંજૂરી આપીને પર્ફોર્મન્સમાં નાટકીય સુધારો કરી શકે છે.
તેમની વચ્ચેની પસંદગી સરળતા અને પર્ફોર્મન્સ વચ્ચેનો વેપાર-બંધ છે. મોટા લોક્સથી શરૂઆત કરો અને જો પર્ફોર્મન્સ પ્રોફાઇલિંગ દર્શાવે કે લોક સ્પર્ધા એક બોટલનેક છે તો જ ઝીણા-દાણાવાળા લોક્સ તરફ આગળ વધો.
3. હંમેશા તમારા લોક્સ છોડો
લોક છોડવામાં નિષ્ફળતા એ એક વિનાશકારી ભૂલ છે જે તમારી સિસ્ટમને અટકાવી દેશે. આ ભૂલનો એક સામાન્ય સ્ત્રોત એ છે કે જ્યારે નિર્ણાયક વિભાગમાં અપવાદ અથવા પ્રારંભિક વળતર થાય છે. આને રોકવા માટે, હંમેશા એવા ભાષાના નિર્માણનો ઉપયોગ કરો જે સફાઈની ખાતરી આપે છે, જેમ કે try...finally બ્લોક્સ Java અથવા C# માં, અથવા C++ માં સ્કોપ કરેલા લોક્સ સાથે RAII (સંસાધન પ્રાપ્તિ એ પ્રારંભિકકરણ છે) પેટર્ન.
ઉદાહરણ (try-finally નો ઉપયોગ કરીને સ્યુડોકોડ):
my_lock.acquire();
try {
// નિર્ણાયક વિભાગ કોડ કે જે અપવાદ ફેંકી શકે છે
} finally {
my_lock.release(); // આ એક્ઝિક્યુટ થવાની ખાતરી છે
}
4. કડક લોક ક્રમનું પાલન કરો
ડેડલોકને રોકવા માટે, સૌથી અસરકારક વ્યૂહરચના એ છે કે વર્તુળાકાર રાહની સ્થિતિને તોડવી. બહુવિધ લોક્સ મેળવવા માટે કડક, વૈશ્વિક અને મનસ્વી ક્રમ સ્થાપિત કરો. જો કોઈ થ્રેડને ક્યારેય લોક A અને લોક B બંને પકડવાની જરૂર હોય, તો તેણે હંમેશા લોક B મેળવતા પહેલા લોક A મેળવવું આવશ્યક છે. આ સરળ નિયમ વર્તુળાકાર રાહને અશક્ય બનાવે છે.
5. લોકિંગના વિકલ્પો ધ્યાનમાં લો
જ્યારે મૂળભૂત હોવા છતાં, લોક્સ સમવર્તી નિયંત્રણ માટેનો એકમાત્ર ઉપાય નથી. ઉચ્ચ-પર્ફોર્મન્સ સિસ્ટમ્સ માટે, અદ્યતન તકનીકોનું અન્વેષણ કરવું યોગ્ય છે:
- લોક-મુક્ત ડેટા સ્ટ્રક્ચર્સ: આ ઓછી-સ્તરની એટોમિક હાર્ડવેર સૂચનાઓ (જેમ કે કમ્પેર-એન્ડ-સ્વેપ) નો ઉપયોગ કરીને ડિઝાઇન કરાયેલ અત્યાધુનિક ડેટા સ્ટ્રક્ચર્સ છે જે લોક્સનો ઉપયોગ કર્યા વિના સમવર્તી ઍક્સેસની મંજૂરી આપે છે. તેમને યોગ્ય રીતે અમલમાં મૂકવું ખૂબ મુશ્કેલ છે પરંતુ ઉચ્ચ સ્પર્ધા હેઠળ ઉત્તમ પર્ફોર્મન્સ પ્રદાન કરી શકે છે.
- અપરિવર્તનશીલ ડેટા: જો ડેટા બનાવવામાં આવ્યા પછી ક્યારેય સુધારવામાં ન આવે, તો તેને સિંક્રોનાઇઝેશનની કોઈપણ જરૂરિયાત વિના થ્રેડો વચ્ચે મુક્તપણે શેર કરી શકાય છે. આ કાર્યાત્મક પ્રોગ્રામિંગનો મુખ્ય સિદ્ધાંત છે અને સમવર્તી ડિઝાઇન્સને સરળ બનાવવા માટે એક વધુને વધુ લોકપ્રિય રીત છે.
- સોફ્ટવેર ટ્રાન્ઝેક્શનલ મેમરી (STM): એક ઉચ્ચ-સ્તરનું એબ્સ્ટ્રેક્શન જે ડેવલપર્સને મેમરીમાં એટોમિક ટ્રાન્ઝેક્શન્સને વ્યાખ્યાયિત કરવાની મંજૂરી આપે છે, જે ડેટાબેઝમાં હોય તેવું જ છે. STM સિસ્ટમ પડદા પાછળની જટિલ સિંક્રોનાઇઝેશન વિગતોનું સંચાલન કરે છે.
નિષ્કર્ષ
લોક-આધારિત સિંક્રોનાઇઝેશન સમવર્તી પ્રોગ્રામિંગનો આધારસ્તંભ છે. તે શેર કરેલા સંસાધનોને સુરક્ષિત કરવા અને ડેટા ભ્રષ્ટાચારને રોકવા માટે એક શક્તિશાળી અને સીધો માર્ગ પ્રદાન કરે છે. સરળ મ્યુટેક્સથી લઈને વધુ સૂક્ષ્મ રીડ-રાઇટ લોક સુધી, આ પ્રિમિટિવ્સ મલ્ટી-થ્રેડેડ એપ્લિકેશન્સ બનાવતા કોઈપણ ડેવલપર માટે આવશ્યક સાધનો છે.
જોકે, આ શક્તિ જવાબદારીની માંગ કરે છે. સંભવિત ખામીઓ—ડેડલોક, લાઇવલોક અને પર્ફોર્મન્સ ડિગ્રેડેશન—નું ઊંડાણપૂર્વકનું જ્ઞાન વૈકલ્પિક નથી. નિર્ણાયક વિભાગના કદને ઘટાડવા, યોગ્ય લોક દાણાદારતા પસંદ કરવા અને કડક લોક ક્રમ લાગુ કરવા જેવી શ્રેષ્ઠ પ્રથાઓનું પાલન કરીને, તમે તેના જોખમોને ટાળીને સમવર્તીતાની શક્તિનો ઉપયોગ કરી શકો છો.
સમવર્તીતામાં નિપુણતા એ એક યાત્રા છે. તેને સાવચેતીપૂર્વક ડિઝાઇન, કડક પરીક્ષણ અને એવી માનસિકતાની જરૂર છે જે હંમેશા સમાંતર રીતે થ્રેડો ચાલતી વખતે થઈ શકે તેવી જટિલ ક્રિયાપ્રતિક્રિયાઓથી વાકેફ હોય. લોકિંગની કળામાં નિપુણતા મેળવીને, તમે એવું સોફ્ટવેર બનાવવા તરફ એક મહત્વપૂર્ણ પગલું ભરો છો જે ફક્ત ઝડપી અને પ્રતિભાવશીલ જ નહીં, પણ મજબૂત, વિશ્વસનીય અને યોગ્ય પણ છે.